#pragma once
#ifndef __SHADERMANAGER_H
#define __SHADERMANAGER_H

#include "Engine.h"
#include "Singleton.h"
#include <string>
#include <iostream>
#include <vector>

using namespace std;



class CShader
{
private:
	GLhandleARB _prog;
	vector<GLhandleARB> _shaders;
	void _logMessage(GLhandleARB object)
	{
		int infoLogLength = 0;
		glGetObjectParameterivARB(object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infoLogLength);
		char *buffer = new char[infoLogLength + 1];
		glGetInfoLogARB(object, infoLogLength, 0, buffer);
		buffer[infoLogLength] = 0x0;
//		CConsole::getInstance()->pushLine(buffer);
	}
public:
	CShader():_prog(0){}
	~CShader()
	{
		for(vector<GLhandleARB>::const_iterator it = _shaders.begin(); it != _shaders.end(); it++)
		{
			glDetachObjectARB(_prog, *it);
			glDeleteShader(*it);
		}
		glDeleteProgram(_prog);
	}
	BOOL addFile(const char* file, GLenum type)
	{
		_shaders.push_back(glCreateShaderObjectARB(type));
		GLhandleARB shader = _shaders.back();
		DWORD len;
		const GLcharARB* code = (const GLcharARB*) io::CFileManager::getInstance()->getRawData(file, &len);
		glShaderSourceARB(shader, 1, &code, (GLint*)(&len));
		delete [] code;
		glCompileShaderARB(shader);
		GLint status;
		
		glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
		if (status == GL_FALSE)
		{
			_logMessage(shader);
			return FALSE;
		}
		return TRUE;
	}
	BOOL compile(void)
	{
		_prog = glCreateProgramObjectARB();

		for(vector<GLhandleARB>::const_iterator it = _shaders.begin(); it != _shaders.end(); it++)
			glAttachObjectARB(_prog, *it);

		glLinkProgramARB(_prog);
		GLint status;
		glGetProgramiv(_prog, GL_LINK_STATUS, &status);
		if (status == GL_FALSE)
		{
			_logMessage(_prog);
			return FALSE;
		}
		return TRUE;
	}
	void setUniform(const char* name, int value){glUniform1iARB(glGetUniformLocationARB(_prog, name), value);}
	void setUniform(const char* name, float value){glUniform1fARB(glGetUniformLocationARB(_prog, name), value);}
	void setUniform(const char* name, float v1, float v2){glUniform2fARB(glGetUniformLocationARB(_prog, name), v1, v2);}
	void setUniform(const char* name, float v1, float v2, float v3){glUniform3fARB(glGetUniformLocationARB(_prog, name), v1, v2, v3);}
	void setUniform(const char* name, float v1, float v2, float v3, float v4){glUniform4fARB(glGetUniformLocationARB(_prog, name), v1, v2, v3, v4);}
	GLhandleARB getProg(void){return _prog;}
};

#endif